package com.qingcloud.fexecutor.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.qingcloud.base.api.remote.admin.AdminApi;
import com.qingcloud.fexecutor.base.constant.DateFormatterConstant;
import com.qingcloud.base.context.UserContextHolder;
import com.qingcloud.fexecutor.base.enums.DataSourceEnum;
import com.qingcloud.fexecutor.base.enums.PageResourceTypeEnum;
import com.qingcloud.base.exception.WamingException;
import com.qingcloud.base.pojo.AjaxResult;
import com.qingcloud.base.remote.pojo.*;
import com.qingcloud.base.utils.LoginUtils;
import com.qingcloud.fexecutor.mapper.*;
import com.qingcloud.fexecutor.model.*;
import com.qingcloud.fexecutor.pojo.WebPageParam;
import com.qingcloud.fexecutor.pojo.WebProjectDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 已发布前端应用功能
 */
@Service
public class WebPubAppService {

    @Resource
    private WebPubAppMapper webPubAppMapper;

    @Resource
    private WebPubPageMapper webPubPageMapper;

    @Resource
    private WebPubPageResourceMapper webPubPageResourceMapper;

    @Resource
    private WebPubPageVariableMapper webPubPageVariableMapper;

    @Resource
    private ApiBaseMapper apiBaseMapper;

    @Resource
    private ApiDocMapper apiDocMapper;

    @Resource
    private ApiParameterMapper apiParameterMapper;

    @Resource
    private ApiResponseMapper apiResponseMapper;

    @Resource
    private AdminApi adminApi;

    @Resource
    private AppDataSourceMapper appDataSourceMapper;

    @Resource
    private StaticResourceMapper staticResourceMapper;

    @Value("${qingcloud.common.cos-url}")
    private String cosUrl;

    @Value("${qingcloud.common.webapp-url}")
    private String webappUrl;

    /**
     * 分页查询项目
     */
    public PageInfo<WebProjectDTO.PageDTO> query() {
        List<BusinessTypeDTO> result = adminApi.businessAppFilter(UserContextHolder.getUserInfo().getUserId());
        if (CollUtil.isEmpty(result)) {
            return new PageInfo<>(new ArrayList<>());
        }
        //所有有权限的APP ID
        List<Integer> authIdList = result.stream().map(BusinessTypeDTO::getBizCode).filter(StrUtil::isNotBlank)
                .map(Integer::parseInt).toList();

        List<WebProjectDTO.PageDTO> projectList = webPubAppMapper.query(authIdList);
        if (CollUtil.isEmpty(projectList)) {
            return new PageInfo<>(new ArrayList<>());
        }

        List<WebProjectDTO.PageDTO> pageDTOList = new ArrayList<>();
        for (WebProjectDTO.PageDTO it : projectList) {
            if (StrUtil.isNotBlank(it.getCoverUrl())) {
                it.setCoverUrl(cosUrl + it.getCoverUrl());
            }
            it.setAppUrl(webappUrl + it.getAppUrl());
            pageDTOList.add(it);
        }
        return new PageInfo<>(pageDTOList);
    }

    /**
     * 应用详情
     */
    public WebProjectDTO.DetailDTO detail(String appUrl) {
        WebPubApp webPubApp = webPubAppMapper.selectOne(new WebPubApp().setAppUrl(appUrl));
        //检查应用权限
        List<BusinessTypeDTO> result = adminApi.businessAppFilter(UserContextHolder.getUserInfo().getUserId());
        if (CollUtil.isEmpty(result)) {
            throw new WamingException("无权查看此应用");
        }
        //所有有权限的APP ID
        Set<Integer> authIds = result.stream().map(BusinessTypeDTO::getBizCode).filter(StrUtil::isNotBlank)
                .map(Integer::parseInt).collect(Collectors.toSet());
        if (!authIds.contains(webPubApp.getDevAppId())) {
            throw new WamingException("无权查看此应用");
        }
        WebProjectDTO.DetailDTO detailDTO = new WebProjectDTO.DetailDTO();
        BeanUtils.copyProperties(webPubApp, detailDTO);
        detailDTO.setCreateTime(webPubApp.getCreateTime().format(DateFormatterConstant.NORMAL_FULL_FORMATTER));
        //查询所有页面记录
        List<WebPubPage> dataList = webPubPageMapper.select(new WebPubPage().setAppId(webPubApp.getId()));

        //如果用户有项目管理权限
        OrderParam orderParam = new OrderParam();
        orderParam.setUserId(UserContextHolder.getUserInfo().getUserId());
        orderParam.setBusinessTypes("5");
        Set<String> pidSet = adminApi.getOrders(orderParam).stream().map(SysOrderDTO::getOrderId).collect(Collectors.toSet());
        if (pidSet.contains(webPubApp.getProjectId())) {
            detailDTO.setPageTree(getAllPageTree(dataList));
            detailDTO.setAdminFlag(true);
        } else {
            LoginUserDTO loginUserDTO = LoginUtils.getCurrentUser(false);
            AjaxResult ajaxResult = adminApi.findByBizId(2, String.valueOf(webPubApp.getDevAppId()));
            if (ajaxResult == null || !ajaxResult.isSuccessful()) {
                throw new WamingException("权限平台未找到该应用信息");
            }
            FunctionRequest request = new FunctionRequest();
            request.setUserId(loginUserDTO.getUserId());
            request.setMenuType(String.valueOf(ajaxResult.getResult()));
            List<FunctionDTO> functionDTOS = adminApi.getFunctionList(request);
            Set<String> functionSet = functionDTOS.stream().map(FunctionDTO::getId).collect(Collectors.toSet());

            List<WebPubPage> dataListResult = new ArrayList<>();
            if (!webPubApp.getCreateUser().equals(loginUserDTO.getUserId()) && webPubApp.getType() != 2) {
                for (WebPubPage it : dataList) {
                    if (functionSet.contains(it.getFunctionId())) {
                        dataListResult.add(it);
                    }
                }
            } else {
                dataListResult.addAll(dataList);
            }
            detailDTO.setPageTree(getAllPageTree(dataListResult));
            detailDTO.setAdminFlag(false);
            List<String> btnAuthList = functionDTOS.stream().filter(it -> "3".equals(it.getFunctionType()))
                    .map(FunctionDTO::getId).toList();
            detailDTO.setBtnAuths(btnAuthList);
        }
        return detailDTO;
    }

    private boolean hasInFunction(List<FunctionDTO> functionDTOS, String functionId) {
        if (functionDTOS == null || functionDTOS.size() < 1) return false;
        for (FunctionDTO function : functionDTOS) {
            String fId = function.getId();
            if (fId.equals(functionId)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取前端应用菜单树
     */
    private List<WebProjectDTO.PageTree> getAllPageTree(List<WebPubPage> dataList) {
        //所有目录
        List<WebProjectDTO.PageTree> groupList = dataList.stream()
                .filter(it -> Integer.valueOf(1).equals(it.getPageCategory()))
                .map(it -> {
                    WebProjectDTO.PageTree pageTree = new WebProjectDTO.PageTree();
                    BeanUtils.copyProperties(it, pageTree);
                    pageTree.setId(it.getId());
                    pageTree.setName(it.getName());
                    pageTree.setIcon(it.getIcon());
                    return pageTree;
                }).toList();
        //所有页面
        List<WebProjectDTO.PageTree> pageList = dataList.stream()
                .filter(it -> Integer.valueOf(2).equals(it.getPageCategory()))
                .map(it -> {
                    WebProjectDTO.PageTree pageTree = new WebProjectDTO.PageTree();
                    BeanUtils.copyProperties(it, pageTree);
                    pageTree.setId(it.getId());
                    pageTree.setParentId(it.getGroupId());
                    return pageTree;
                }).toList();
        //所有子菜单设置
        Map<Integer, List<WebProjectDTO.PageTree>> pageMap = pageList.stream().collect(Collectors.groupingBy(WebProjectDTO.PageTree::getParentId));
        for (WebProjectDTO.PageTree it : pageList) {
            it.setChildren(pageMap.getOrDefault(it.getId(), Collections.emptyList()));
        }
        if (CollUtil.isEmpty(groupList)) {
            //没有目录
            return pageList.stream().filter(it -> Integer.valueOf(0).equals(it.getParentId())).toList();
        } else {
            for (WebProjectDTO.PageTree it : groupList) {
                it.setChildren(pageMap.getOrDefault(it.getId(), Collections.emptyList()));
            }
            //无组菜单
            List<WebProjectDTO.PageTree> resultList = pageMap.getOrDefault(0, new ArrayList<>());
            resultList.addAll(groupList);
            return resultList;
        }
    }

    /**
     * 页面详情查询
     */
    public WebProjectDTO.WebPageDTO pageDetail(Integer id) {
        //页面信息
        WebPubPage webPubPage = webPubPageMapper.selectByPrimaryKey(id);
        WebProjectDTO.WebPageDTO webPageDTO = new WebProjectDTO.WebPageDTO();
        BeanUtils.copyProperties(webPubPage, webPageDTO);
        //页面源码
        webPageDTO.setSourceContent(webPubPage.getSource());
        //页面关联表和字段
        return webPageDTO;
    }

    /**
     * 查询页面所有资源
     *
     * @param pageId 页面ID
     */
    public Map<String, List<WebPageParam.PageResourceDTO>> findPageResource(Integer pageId) {
        Map<String, List<WebPageParam.PageResourceDTO>> resultMap = new HashMap<>();
        //查询资源
        List<WebPubPageResource> resourceList = webPubPageResourceMapper.select(new WebPubPageResource().setPageId(pageId));
        //数据源
        List<WebPubPageResource> dataSourceList = resourceList.stream().filter(it -> PageResourceTypeEnum.DATA_SOURCE.code.equals(it.getResourceType())).toList();
        if (CollUtil.isNotEmpty(dataSourceList)) {
            List<WebPageParam.PageResourceDTO> dtoList = new ArrayList<>(dataSourceList.size());
            List<String> codes = dataSourceList.stream().map(WebPubPageResource::getRealCode).toList();
            Map<String, AppDataSource> dataSourceMap = appDataSourceMapper.findByCode(dataSourceList.get(0).getAppId(), codes)
                    .stream().collect(Collectors.toMap(AppDataSource::getCode, it -> it, (v1, v2) -> v2));
            for (WebPubPageResource it : dataSourceList) {
                WebPageParam.PageResourceDTO dto = new WebPageParam.PageResourceDTO();
                BeanUtil.copyProperties(it, dto);
                AppDataSource appDataSource = dataSourceMap.get(it.getRealCode());
                if (appDataSource != null) {
                    dto.setDatasourceIcon(DataSourceEnum.getByCode(appDataSource.getType()).icon);
                }
                dtoList.add(dto);
            }
            resultMap.put(PageResourceTypeEnum.DATA_SOURCE.name(), dtoList);
        }
        //API
        List<WebPubPageResource> apiList = resourceList.stream().filter(it -> PageResourceTypeEnum.API.code.equals(it.getResourceType())).toList();
        if (CollUtil.isNotEmpty(apiList)) {
            List<WebPageParam.PageResourceDTO> dtoList = new ArrayList<>(apiList.size());
            List<String> codes = apiList.stream().map(WebPubPageResource::getRealCode).toList();
            Map<String, ApiBase> apiBaseMap = apiBaseMapper.findByCode(apiList.get(0).getAppId(), codes)
                    .stream().collect(Collectors.toMap(ApiBase::getCode, it -> it, (v1, v2) -> v2));
            for (WebPubPageResource it : apiList) {
                WebPageParam.PageResourceDTO dto = new WebPageParam.PageResourceDTO();
                BeanUtil.copyProperties(it, dto);
                ApiBase apiBase = apiBaseMap.get(it.getRealCode());
                if (apiBase != null) {
                    dto.setApiMethod(apiBase.getMethod());
                }
                dtoList.add(dto);
            }
            resultMap.put(PageResourceTypeEnum.API.name(), dtoList);
        }
        //静态资源
        List<WebPubPageResource> staticList = resourceList.stream().filter(it -> PageResourceTypeEnum.STATIC.code.equals(it.getResourceType())).toList();
        if (CollUtil.isNotEmpty(staticList)) {
            List<WebPageParam.PageResourceDTO> dtoList = new ArrayList<>(staticList.size());
            List<String> codes = staticList.stream().map(WebPubPageResource::getRealCode).toList();
            Map<String, StaticResource> staticResourceMap = staticResourceMapper.findByCode(staticList.get(0).getAppId(), codes)
                    .stream().collect(Collectors.toMap(StaticResource::getCode, it -> it, (v1, v2) -> v2));
            for (WebPubPageResource it : staticList) {
                WebPageParam.PageResourceDTO dto = new WebPageParam.PageResourceDTO();
                BeanUtil.copyProperties(it, dto);
                StaticResource staticResource = staticResourceMap.get(it.getRealCode());
                if (staticResource != null) {
                    dto.setGroupId(staticResource.getGroupId());
                    dto.setStaticUrl(cosUrl + staticResource.getUrl());
                }
                dtoList.add(dto);
            }
            resultMap.put(PageResourceTypeEnum.STATIC.name(), dtoList);
        }
        //脚本
        List<WebPubPageResource> scriptList = resourceList.stream().filter(it -> PageResourceTypeEnum.SCRIPT.code.equals(it.getResourceType())).toList();
        if (CollUtil.isNotEmpty(scriptList)) {
            List<WebPageParam.PageResourceDTO> dtoList = new ArrayList<>(scriptList.size());
            for (WebPubPageResource it : scriptList) {
                WebPageParam.PageResourceDTO dto = new WebPageParam.PageResourceDTO();
                BeanUtil.copyProperties(it, dto);
                dtoList.add(dto);
            }
            resultMap.put(PageResourceTypeEnum.SCRIPT.name(), dtoList);
        }
        return resultMap;
    }

    /**
     * 查询页面变量
     */
    public Map<String, Object> findPageVariable(Integer pageId) {
        //页面变量
        Map<String, Object> resultMap = new HashMap<>();
        List<WebPubPageVariable> list = webPubPageVariableMapper.select(new WebPubPageVariable().setPageId(pageId));
        for (WebPubPageVariable it : list) {
            resultMap.putAll(JSONObject.parseObject(it.getVars()));
        }
        //应用变量
        WebPubPage pubPage = webPubPageMapper.selectByPrimaryKey(pageId);
        WebPubPageVariable appVar = webPubPageVariableMapper.selectOne(new WebPubPageVariable().setAppId(pubPage.getAppId()).setType(3));
        if (Objects.nonNull(appVar)) {
            resultMap.putAll(JSONObject.parseObject(appVar.getVars()));
        }
        //当前用户登录信息
        JSONObject user = new JSONObject();
        LoginUserDTO userInfo = UserContextHolder.getUserInfo();
        if (Objects.nonNull(userInfo)) {
            LoginUserDTO loginUserDTO = adminApi.findUserById(userInfo.getUserId());
            user.put("id", userInfo.getUserId());
            user.put("email", loginUserDTO.getWorkEmail());
            user.put("name", loginUserDTO.getFullName());
        }
        resultMap.put("currentUser", user);
        return resultMap;
    }
}
